package com.humble.vichatbackend.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.humble.vichatbackend.model.enums.ErrorCode;
import com.humble.vichatbackend.common.UserRegisterRequest;
import com.humble.vichatbackend.constant.UserConstant;
import com.humble.vichatbackend.exception.BusinessException;
import com.humble.vichatbackend.model.domain.User;
import com.humble.vichatbackend.model.vo.UserVO;
import com.humble.vichatbackend.service.UserService;
import com.humble.vichatbackend.mapper.UserMapper;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.math3.util.Pair;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;

import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static org.apache.commons.lang3.math.NumberUtils.min;

/**
 * @author jhhuang
 * @description 针对表【user(用户)】的数据库操作Service实现
 * @createDate 2025-07-22 10:04:28
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {
    private final String salt = "HUMBLE";

    @Resource
    private UserMapper userMapper;

    @Override
    public Long register(UserRegisterRequest userRegisterRequest) {
        String username = userRegisterRequest.getUsername();
        String userAccount = userRegisterRequest.getUserAccount();
        String avatarUrl = userRegisterRequest.getAvatarUrl();
        Integer gender = userRegisterRequest.getGender();
        String userPassword = userRegisterRequest.getUserPassword();
        String checkPassword = userRegisterRequest.getCheckPassword();
        String tags = userRegisterRequest.getTags();

        if (StringUtils.isAnyBlank(username, userAccount, userPassword, checkPassword)) {
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }
        if(userPassword.length() !=checkPassword.length()||!userPassword.equals(checkPassword)) {
            throw new BusinessException("两次输入密码不相同", 40000, "");
        }
        if (userPassword.length() > 20 || userPassword.length() < 6) {
            throw new BusinessException("密码长度不合规，长度应在[6,20]", 40000, "");
        }
        if (userAccount.length() > 20 || userAccount.length() < 6) {
            throw new BusinessException("账号长度不合规，长度应在[6,20]", 40000, "");
        }
        //排除账号中特殊字符
        String validPattern = "[`~!@#$%^&*()+=|{}':;',\\\\[\\\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";
        Pattern compile = Pattern.compile(validPattern);
        Matcher matcher = compile.matcher(userAccount);
        if (matcher.find()) {
            throw new BusinessException("账号不能出现特殊字符，仅能包含数字或字母", 40000, "");
        }

        //账号是否重复
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
        queryWrapper.eq("user_account", userAccount).eq("phone", userAccount);
        User repeatUser = userMapper.selectOne(queryWrapper);
        if(repeatUser != null) {
            throw new BusinessException("账号重复，请重新输入", 40000, "");
        }

        //获取加密密码
        String enctypePassword = DigestUtils.md5DigestAsHex((userPassword+salt).getBytes());

        User user = new User();
        user.setUsername(username);
        user.setUserAccount(userAccount);
        user.setAvatarUrl(avatarUrl!=null?avatarUrl:"");
        user.setGender(gender!=null?gender:2);
        user.setUserPassword(enctypePassword);
        user.setTags(tags!=null?tags:"");
        int insert = userMapper.insert(user);
        log.info("用户注册成功！用户名：{}，账号：{}", username, userAccount);
        return user.getId();

    }

    @Override
    public UserVO userLogin(String account, String password, HttpServletRequest request) {
        if(StringUtils.isAnyBlank(account,password)) {
            throw new BusinessException("缺少登录参数", 40000, "");
        }
        if(account.length()>20||account.length()<6) {
            throw new BusinessException("账号长度异常", 40000, "");
        }
        if(password.length()>20||password.length()<6) {
            throw new BusinessException("密码长度异常", 40000, "");
        }
        String enctypePassword = DigestUtils.md5DigestAsHex((password + salt).getBytes());
        //支持账号、手机、邮箱登录
        QueryWrapper<User> eq = new QueryWrapper<User>().and(wrapper->wrapper.eq("user_account", account)
                .or().eq("phone", account).or().eq("email", account)).eq("user_password", enctypePassword);
        List<User> users = userMapper.selectList(eq);
        if(users.size()>1) {
            log.error("用户登录时，使用账户出现多个相符用户信息，登录账号：{}",account);
            throw new BusinessException("用户系统出现异常", 50000, "");
        }
        if(users.size()<1){
            return null;
        }
        User schemeUser = users.get(0);

        if(!enctypePassword.equals(schemeUser.getUserPassword())) {
            throw new BusinessException("账户密码有误",40101);
        }
        UserVO safeUser = UserVO.getSafeUser(schemeUser);

        request.getSession().setAttribute(UserConstant.USER_LOGIN_STATE, safeUser);
        return safeUser;
    }

    @Override
    public Integer userLogout(HttpServletRequest request) {
        request.getSession().removeAttribute(UserConstant.USER_LOGIN_STATE);
        return 1;
    }

    @Override
    public List<UserVO> searchUsers(String username) {
        if(StringUtils.isBlank(username)) {
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }
        List<User> users = userMapper.selectList(new QueryWrapper<User>().eq("username", username));
        List<UserVO> safeUsers = users.stream().map(user -> UserVO.getSafeUser(user)).collect(Collectors.toList());
        return safeUsers;
    }

    @Override
    public List<UserVO> searchUserByTags(List<String> tags) {
        if(tags == null || tags.isEmpty()) {
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }
        log.info("开始根据标签帅选用户，标签为：{}",tags.toString());
        //先用第一个标签再数据库中过滤部分用户；
        List<User> users = userMapper.selectList(new QueryWrapper<User>().like("tags", tags.get(0)));

        //在内存中使用剩余标签进行过滤
        Gson gson = new Gson();
        List<UserVO> safeUsers = users.stream().filter(user -> {
            String userTags = user.getTags();
            Set<String> tagSet = gson.fromJson(userTags, new TypeToken<Set<String>>() {
            }.getType());
            for (int i = 1; i < tags.size(); i++) {
                if (!tagSet.contains(tags.get(i))) {
                    return false;
                }
            }
            return true;
        }).map(UserVO::getSafeUser).collect(Collectors.toList());
        log.info("筛选得到的用户：{}",safeUsers.stream().map(user->{return user.getUsername();}).collect(Collectors.toList()).toString());
        return safeUsers;
        
    }

    @Override
    public Integer updateUser(User user,UserVO currentUser,HttpServletRequest request) {
        if(StringUtils.isBlank(currentUser.getUserAccount())||user==null) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR);
        }
        if(currentUser.getUserRole()!=UserConstant.ADMIN_ROLE&&!user.getUserAccount().equals(currentUser.getUserAccount())) {
            throw new BusinessException("权限不足，不得修改其他用户信息", 40101, "");
        }
        User oldUser = userMapper.selectOne(new QueryWrapper<User>().eq("user_account", user.getUserAccount()));
        if(oldUser==null) {
            throw new BusinessException("需要修改用户不存在", 40000, "");
        }
        User changeUser = new User();
        changeUser.setId(null);
        changeUser.setUsername(StringUtils.isBlank(user.getUsername())?null:user.getUsername());
        changeUser.setUserAccount(null);
        changeUser.setAvatarUrl(StringUtils.isBlank(user.getAvatarUrl())?null:user.getAvatarUrl());
        changeUser.setGender(user.getGender());
        changeUser.setUserPassword(null);
        changeUser.setPhone(StringUtils.isBlank(user.getPhone())?null:user.getPhone());
        changeUser.setEmail(StringUtils.isBlank(user.getEmail())?null:user.getEmail());
        changeUser.setUserStatus(null);
        changeUser.setCreateTime(null);
        changeUser.setUpdateTime(null);
        changeUser.setIsDelete(null);
        changeUser.setUserRole(null);
        changeUser.setTags(StringUtils.isBlank(user.getTags())?null:user.getTags());

        changeUser.setUserAccount(user.getUserAccount());
        log.info("修改用户信息开始，原用户信息：{}",oldUser.toString());
        int count = userMapper.update(changeUser, new UpdateWrapper<User>().eq("user_account", oldUser.getUserAccount()));
        //根据条件更新当前用户
        if(oldUser.getUserAccount().equals(currentUser.getUserAccount())) {
            currentUser.setUsername(StringUtils.isBlank(user.getUsername())?null:user.getUsername());
            changeUser.setAvatarUrl(StringUtils.isBlank(user.getAvatarUrl())?null:user.getAvatarUrl());
            changeUser.setPhone(StringUtils.isBlank(user.getPhone())?null:user.getPhone());
            changeUser.setEmail(StringUtils.isBlank(user.getEmail())?null:user.getEmail());
            changeUser.setTags(StringUtils.isBlank(user.getTags())?null:user.getTags());

            request.getSession().setAttribute(UserConstant.USER_LOGIN_STATE, currentUser);
        }

        if(count>=0) {
            log.info("修改用户信息成功，用户新信息{}", user.toString());
        }
        return count;
    }

    @Override
    public Boolean isAdmin(HttpServletRequest request) {
        UserVO current = (UserVO)request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
        if(current==null){
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }
        return current.getUserRole()==UserConstant.ADMIN_ROLE;
    }

    @Override
    public Integer deleteUser(Long id) {
        if(id==null){
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }
        return userMapper.deleteById(id);
    }

    public UserVO getCurrentUser(HttpServletRequest request){
        UserVO currentUser = (UserVO)request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
        if(currentUser==null){
            throw new BusinessException("登录状态失效，请重新登录!",40100);
        }
        return currentUser;
    }

    @Override
    public List<UserVO> getRecommendUser(UserVO currentUser, int size) {
        String tags = currentUser.getTags();
        Gson gson = new Gson();
        List<String> currentUserTags = gson.fromJson(tags, new TypeToken<ArrayList<String>>() {}.getType());

        LambdaQueryWrapper<User> userQueryWrapper = new QueryWrapper<User>().lambda();
        userQueryWrapper.isNotNull(User::getTags);
        userQueryWrapper.isNotNull(User::getUsername);
        userQueryWrapper.ne(User::getId,currentUser.getId());

        List<User> userList = userMapper.selectList(userQueryWrapper);

        //index -> level
        List<Pair<Integer,Integer>> rankList = new ArrayList<>();
        for (int i = 0; i < userList.size(); i++) {
            String otherTags = userList.get(i).getTags();
            if(StringUtils.isEmpty(otherTags)){
                continue;
            }
            List<String> userTags =gson.fromJson(otherTags, new TypeToken<ArrayList<String>>() {}.getType());
            //获取最短编辑距离
            int level = minDistance(currentUserTags, userTags);
            rankList.add(new Pair<>(i,level));
        }

        rankList.sort(new Comparator<Pair<Integer,Integer>>() {

            @Override
            public int compare(Pair<Integer, Integer> o1, Pair<Integer, Integer> o2) {
                return o1.getValue()-o2.getValue();
            }
        });

        return rankList.subList(0,size).stream().map((pair)->{
            return UserVO.getSafeUser(userList.get(pair.getKey()));
        }).collect(Collectors.toList());
    }


    //最短编辑距离算法
    public int minDistance(List<String> tags1, List<String> tags2) {
        if (CollectionUtils.isEmpty(tags1) || CollectionUtils.isEmpty(tags2)) {
            log.error("距离编辑算法获取参数为空");
        }
        int[][] dp = new int[tags1.size() + 1][tags2.size() + 1];
        //初始化DP数组
        for (int i = 0; i <= tags1.size() ; i++) {
            dp[i][0] = i;
        }
        for (int i = 0; i <= tags2.size() ; i++) {
            dp[0][i] = i;
        }
        int cost = 1;
        for (int i = 1; i <= tags1.size() ; i++) {
            for (int j = 1; j <= tags2.size() ; j++) {
                boolean flag = true;
                for(String tag2:tags2){
                    if (tags1.get(i - 1).equals(tag2)) {
                        cost = 0;
                        flag = false;
                        break;
                    }
                }
                if(flag){
                    cost = 1;
                }
                dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost);
            }
        }
        return dp[tags1.size()][tags2.size()];
    }

}




